package com.lenovo.locationmanager;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Location;
import android.location.LocationManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;

import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;


public class GpsService extends Service {
    private static final String TAG = GpsService.class.getSimpleName();

    private final IBinder mBinder = new LocalBinder();
    public LocationManager locationManager = null;
    private GpsLocationListener locationListener = null;
    private GpsStatusListener statusListener = null;
    //当前测试的序号
    public int mCurrentSessionNo = 0;
    //总测试序号
    private int mTotalSession;
    //测试之间间隔时间
    private int mTimeBetweenSessions;
    //超时时间
    private int mOvertime;
    //热启动还是冷启动
    private boolean mIsHot;
    //失败后重连次数
    private int mRetryTimes;
    //起始时间
    private long startTime = 0;
    //结束时间
    private long endTime = 0;
    //ttff定位成功与否
    private boolean isTTFFLocated = false;
    //卫星定位成功与否
    private boolean isSateLocated = false;
    //是否在定位中
    private boolean isInFix = false;
    //是否在执行任务中
    private boolean isInTask = false;
    //
    private boolean isInRetry = false;
    //定位失败的Counter
    private int failCounter = 0;
    //定位结果数据的list
    //private List<FixResult> mFixResultList = new ArrayList<>();
    //单次定位结果
    private FixResult mFixResult = new FixResult();
    //保存的文件夹名称
    private String dirName;
    private FileUtils fileUtils = new FileUtils();
    //定位输出Writer
    private FileWriter locationFileWriter;
    //Gps卫星数据输出Writer
    private FileWriter gpsFileWriter;

    private SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
    private String trueLongitude;
    private String trueLatitude;

    private static final int CHECK_FIX_RESULT = 101;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CHECK_FIX_RESULT:
                    //每隔一秒检查定位成功没有
                    handler.postDelayed(mFixResultRunnable, Constant.SECOND);
                    break;
            }
        }
    };

    private Runnable mFixDelayRunnable = new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "mFixDelayRunnable:------------------ ");
            if (isSateLocated && isTTFFLocated) {
                //定位成功
//                if (isInRetry) {
                //重试成功
                isInRetry = false;
                failCounter = 0;
//                }
                mCurrentSessionNo++;
                startFix();
            } else {
                //定位失败
                if (isInRetry) {
                    //重试再失败
                    if (failCounter < mRetryTimes) {
                        failCounter++;
                        isInRetry = true;
                        startFix();
                    } else {
                        isInRetry = false;
                        failCounter = 0;
                        mCurrentSessionNo++;
                        startFix();
                    }

                } else {
                    //定位失败，第一次重试
                    if (failCounter < mRetryTimes) {
                        failCounter++;
                        isInRetry = true;
                        startFix();
                    } else {
                        failCounter = 0;
                        mCurrentSessionNo++;
                        startFix();
                    }

                }
            }

        }
    };

    private long spentTime;
    private Runnable mFixResultRunnable = new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "mFixResultRunnable: -----------------");
            spentTime = System.currentTimeMillis() - GpsService.this.startTime;
            if (!(isSateLocated && isTTFFLocated) && spentTime <= mOvertime * Constant.SECOND) {
                handler.postDelayed(mFixResultRunnable, Constant.SECOND);
                return;
            }

            //查看定位结果
            if (mFixResult.getTtff() != -1 && mFixResult.getLocation() != null) {
                //定位成功
                Toast.makeText(GpsService.this, "定位成功", Toast.LENGTH_SHORT).show();
            } else {
                //定位失败
                Toast.makeText(GpsService.this, "定位失败", Toast.LENGTH_SHORT).show();
            }
            stopFix();
            endTime = System.currentTimeMillis();
            mFixResult.setEndTime(df.format(new Date(endTime)));
            //保存数据
            new Thread() {
                @Override
                public void run() {
                    outputResult(GpsService.this.mFixResult);
                }
            }.start();


            //测试之间间隔时间
            GpsService.this.handler.postDelayed(mFixDelayRunnable,
                    mTimeBetweenSessions * Constant.SECOND);

        }
    };

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        Bundle bundle = null;

        @Override
        public void onReceive(Context context, Intent intent) {
            //TTFF
            if (intent.getAction().equals(GpsIntent.TIME_TO_FIRST_FIX)) {
                bundle = intent.getExtras();
                mFixResult.setTtff(bundle.getInt(GpsIntent.TTFF));
                isTTFFLocated = true;
            }
            if (intent.getAction().equals(GpsIntent.GPS_SATELLITE_INFO)) {
                bundle = intent.getExtras();
                SatelliteResult result =
                        (SatelliteResult) bundle.getSerializable(GpsIntent.SATELLITES);
                List<com.lenovo.locationmanager.GpsSatellite> gpsSatelliteList =
                        result.getGpsSatellites();
                mFixResult.setGpsSatellites(gpsSatelliteList);
                for (GpsSatellite gpsSatellite : gpsSatelliteList) {
                    if (gpsSatellite.ismUsedInFix()) {
                        isSateLocated = true;
                        return;
                    }
                }
            }
            if (intent.getAction().equals(GpsIntent.GPS_LOCATION_INFO)) {
                bundle = intent.getExtras();
                mFixResult.setLocation((Location) bundle.getParcelable(GpsIntent.LOCATION));
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        registerReceiver();
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        locationListener = new GpsLocationListener(this);
        statusListener = new GpsStatusListener(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterListeners();
        unregisterReceiver();
        closeWriter();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    private boolean isReceiverRegistered = false;

    //注册广播监听器
    private void registerReceiver() {
        IntentFilter gpsBroadcastFilter = new IntentFilter();
        gpsBroadcastFilter.addAction(GpsIntent.TIME_TO_FIRST_FIX);
        gpsBroadcastFilter.addAction(GpsIntent.GPS_SATELLITE_INFO);
        gpsBroadcastFilter.addAction(GpsIntent.GPS_LOCATION_INFO);
        registerReceiver(this.mReceiver, gpsBroadcastFilter);
        isReceiverRegistered = true;
    }

    //注销广播监听器
    private void unregisterReceiver() {
        this.unregisterReceiver(mReceiver);
        isReceiverRegistered = false;
    }

    /**
     * 开启一次压力测试任务
     *
     * @param times         次数
     * @param interval_time 间隔时间
     * @param overtime      超时时间
     * @param retry_times   重试次数
     * @param isHot         热启动/冷启动
     */
    public void startTask(int times, int interval_time, int overtime, int retry_times,
                          boolean isHot) {
        this.mTotalSession = times;
        this.mTimeBetweenSessions = interval_time;
        this.mOvertime = overtime;
        this.mRetryTimes = retry_times;
        this.mIsHot = isHot;
        trueLongitude = SpUtils.getInputLongitude(GpsService.this);
        trueLatitude = SpUtils.getInputLatitude(GpsService.this);
        //创建输出流，输出标题
        dirName = fileNameWithExtension("");
        locationFileWriter = fileUtils.getFileWriter(dirName, FileUtils.LOCATION, "location.csv");
        gpsFileWriter = fileUtils.getFileWriter(dirName, FileUtils.SATELLITE, "satellite.csv");
        new Thread() {
            @Override
            public void run() {
                fileUtils.writeTitle(FileUtils.LOCATION, locationFileWriter);
                fileUtils.writeTitle(FileUtils.SATELLITE, gpsFileWriter);
            }
        }.start();
        //从第一次开始测试
        mCurrentSessionNo = 1;
        isInTask = true;
        startFix();
    }

    /**
     * 中止测试任务
     */
    public void stopTask() {
        //如果在定位中，关闭定位
        if (isInFix) {
            stopFix();
        }
        isInTask = false;
        //关闭输出流
        dirName = "";
        closeWriter();
        //发广播，测试任务结束
        Intent intent = new Intent(GpsIntent.GPS_TASK_FINISH);
        this.sendBroadcast(intent);
    }

    /**
     * 开始单次定位
     */
    public void startFix() {
        //优先判断
        if (!isInTask || mCurrentSessionNo > mTotalSession) {
            stopTask();
            return;
        }
        isSateLocated = false;
        isTTFFLocated = false;
        isInFix = true;
        //清楚单次数据
        mFixResult.clearCache();
        mFixResult.setSessionNo(mCurrentSessionNo);
        mFixResult.setFailCounter(failCounter);


        Intent startFixIntent = new Intent(GpsIntent.GPS_START_FIX);
        startFixIntent.putExtra(GpsIntent.CURRENT_SESSION, mCurrentSessionNo);
        startFixIntent.putExtra(GpsIntent.TOTAL_SESSION, mTotalSession);
        startFixIntent.putExtra(GpsIntent.CURRENT_RETRY, failCounter);
        startFixIntent.putExtra(GpsIntent.TOTAL_RETRY, mRetryTimes);
        GpsService.this.sendBroadcast(startFixIntent);

        startTime = System.currentTimeMillis();
        mFixResult.setStartTime(df.format(new Date(startTime)));
        if (!mIsHot) {
            deleteAidingData();
        }
        //添加定位
        registerListeners();
        handler.sendEmptyMessage(CHECK_FIX_RESULT);
    }

    /**
     * 中止单次定位
     */
    public void stopFix() {
        isInFix = false;
        unregisterListeners();
        startTime = 0;
        endTime = 0;
    }


    private void deleteAidingData() {
        Log.d(TAG, "deleteAidingData: ---------------------");
        locationManager.sendExtraCommand(LocationManager.GPS_PROVIDER,
                "delete_aiding_data", null);
    }

    private void registerListeners() {
        //添加定位监听
        if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0.0f,
                    locationListener);
        }
        //添加GPSStatus监听
        locationManager.addGpsStatusListener(statusListener);
    }

    private void unregisterListeners() {
        //释放资源
        locationManager.removeUpdates(locationListener);
        locationManager.removeGpsStatusListener(statusListener);
    }

    /**
     * 每一次将定位结果输出到外部存储中
     *
     * @param fixResult
     * @return
     */
    private void outputResult(FixResult fixResult) {
        //保存定位数据
        Location location = fixResult.getLocation();
        try {
            if (location != null) {
                locationFileWriter.write(fixResult.getSessionNo() + ","
                        + fixResult.getFailCounter() + ","
                        + Utils.formatUTC(location.getTime(), "yyyy-MM-dd HH:mm:ss") + ","
                        + fixResult.getStartTime() + ","
                        + fixResult.getEndTime() + ","
                        + fixResult.getTtff() + ","
                        + location.getLongitude() + ","
                        + location.getLatitude() + ","
                        + location.getAltitude() + ","
                        + trueLongitude + ","
                        + trueLatitude + ","
                        + Utils.getDistance(location.getLongitude(), location.getLatitude(),
                        Double.parseDouble(trueLongitude), Double.parseDouble(trueLatitude)) +
                        "\r\n"
                );
            } else {
                locationFileWriter.write(fixResult.getSessionNo() + ","
                        + fixResult.getFailCounter() + ","
                        + " " + ","
                        + fixResult.getStartTime() + ","
                        + fixResult.getEndTime() + ","
                        + " " + ","
                        + " " + ","
                        + " " + ","
                        + " " + "\r\n"
                );
            }
            locationFileWriter.flush();

            if (fixResult.getGpsSatellites() != null) {
                //保存卫星数据
                for (GpsSatellite gpsSatellite : fixResult.getGpsSatellites()) {
                    gpsFileWriter.write(fixResult.getSessionNo() + "," + fixResult.getFailCounter() + "," + gpsSatellite.getmPrn() + "," + gpsSatellite.getmSnr() + "," + gpsSatellite.getmElevation()
                            + "," + gpsSatellite.getmAzimuth() + "," + Utils.getSatelliteFlags(gpsSatellite) + "\r\n");
                }
                gpsFileWriter.write("\r\n");
            }
            gpsFileWriter.flush();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String fileNameWithExtension(String extension) {
        return "Logs_" + new SimpleDateFormat("yyyy-MM-dd-hh.mm.ss").format(new Date()) + extension;
    }

//    /**
//     * 返回查询条件
//     *
//     * @return
//     */
//    private Criteria getCriteria() {
//        Criteria criteria = new Criteria();
//        //设置定位精确度 Criteria.ACCURACY_COARSE比较粗略，Criteria.ACCURACY_FINE则比较精细
//        criteria.setAccuracy(Criteria.ACCURACY_FINE);
//        //设置是否要求速度
//        criteria.setSpeedRequired(true);
//        // 设置是否允许运营商收费
//        criteria.setCostAllowed(true);
//        //设置是否需要方位信息
//        criteria.setBearingRequired(true);
//        //设置是否需要海拔信息
//        criteria.setAltitudeRequired(true);
//        // 设置对电源的需求
//        criteria.setPowerRequirement(Criteria.POWER_LOW);
//        return criteria;
//    }

    public class LocalBinder extends Binder {
        public GpsService getService() {
            return GpsService.this;
        }
    }

    private void closeWriter() {
        try {
            if (locationFileWriter != null) {
                locationFileWriter.close();
            }
            if (gpsFileWriter != null) {
                gpsFileWriter.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



}
